/**
 *
 *
 */
package org.jiscinvolve.astrodabis.barberry.control;

import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.RequestAttributes;

import org.jiscinvolve.astrodabis.barberry.common.core.Tag;
import org.jiscinvolve.astrodabis.barberry.common.core.Job;
import org.jiscinvolve.astrodabis.barberry.common.core.Account;
import org.jiscinvolve.astrodabis.barberry.common.core.Womble;
import org.jiscinvolve.astrodabis.barberry.common.core.Identifier;

import org.jiscinvolve.astrodabis.barberry.common.data.TapService;
import org.jiscinvolve.astrodabis.barberry.common.data.TapTable;
import org.jiscinvolve.astrodabis.barberry.common.data.TapColumn;
import org.jiscinvolve.astrodabis.barberry.common.data.TapJoin;
import org.jiscinvolve.astrodabis.barberry.common.data.TapRow;
import org.jiscinvolve.astrodabis.barberry.common.data.RowTag;
import org.jiscinvolve.astrodabis.barberry.common.data.JoinTag;

public class RequestData
    {

    /**
     * Our debug logger.
     * 
     */
    private static Log log = LogFactory.getLog(RequestData.class);

    /**
     * Spring model attribute name.
     *
     */
    public static final String MODEL_ATTRIB = "request-data" ;

    public RequestData(WebRequest request, Womble womble, Account actor)
        {
        this(
            null,
            request,
            womble,
            actor
            );
        }

    // Is this one used ?
    public RequestData(BaseController controller, WebRequest request, Womble womble, Account actor)
        {
        this.actor = actor ;
        this.womble = womble ;
        this.request = request ;
        this.controller = controller ;
        }

    // Is this used ?
    private BaseController controller ;
    public  BaseController controller()
        {
        return this.controller ;
        }

    private WebRequest request ;

    private Womble womble ;
    public Womble womble()
        {
        return this.womble ;
        }

    private Account actor ;
    public Account actor()
        {
        return this.actor ;
        }

    /**
     * Inner class for building URL paths.
     * @todo Move the path tools to a separate class ?
     *
     */
    public static class PathBuilder
        {
        private String last = null ;

        public PathBuilder(String path)
            {
            builder = new StringBuilder(
                path
                );
            }

        private StringBuilder builder ;

        public void append(String path)
            {
            if (path != null)
                {
                builder.append(
                    "/"
                    );
                builder.append(
                    path
                    );
                }
            }

        public void append(Identifier ident)
            {
            if (ident != null)
                {
                append(
                    ident.value().toString()
                    );
                }
            }

        public void append(Account account)
            {
            append(
                Paths.ACCOUNT_PATH
                );
            append(
                account.ident()
                );
            }

        public void append(Tag tag)
            {
            append(
                Paths.TAG_PATH
                );
            append(
                tag.ident()
                );
            }

        public void append(Job job)
            {
            append(
                Paths.JOB_PATH
                );
            append(
                job.ident()
                );
            }

        public void append(RowTag rowtag)
            {
            append(
                Paths.ROWTAG_PATH
                );
            append(
                rowtag.ident()
                );
            }

        public void append(JoinTag jointag)
            {
            append(
                Paths.JOINTAG_PATH
                );
            append(
                jointag.ident()
                );
            }

        public void append(TapRow row)
            {
            append(
                Paths.ROW_PATH
                );
            append(
                row.ident()
                );
            }

        public void append(TapJoin tapjoin)
            {
            append(
                Paths.JOIN_PATH
                );
            append(
                tapjoin.ident()
                );
            }

        public void append(TapColumn column)
            {
            append(
                Paths.COLUMN_PATH
                );
            append(
                column.ident()
                );
            }

        public void append(TapTable table)
            {
            append(
                Paths.TABLE_PATH
                );
            append(
                table.ident()
                );
            }

        public void append(TapService service)
            {
            append(
                Paths.SERVICE_PATH
                );
            append(
                service.ident()
                );
            }




        static String  REGEX_PATTERN = "/{2,}" ;
        static Pattern pattern ;
        static {
            try {
                pattern = Pattern.compile(
                    REGEX_PATTERN
                    );
                }
            catch (Exception ouch)
                {
                log.error("Failed to compile regex pattern [" + REGEX_PATTERN + "][" + ouch.getMessage() + "]");
                }
            }

        @Override
        public String toString()
            {
            // Removes duplicate slashes.
            return pattern.matcher(
                builder.toString()
                ).replaceAll(
                    "/"
                    );
            }
        }

    /**
     * The Spring redirect URI prefix.
     * 
     */
    public static final String REDIRECT_PREFIX = "redirect:" ;

    /**
     * The URL path for our Spring dispatcher servlet.
     * 
     */
    public static final String SERVLET_PATH = "/" ;

    /**
     * The URL path for our static content.
     * 
     */
    public static final String STATIC_PATH = "/static" ;

    /**
     * Inner class for redirect links to MCV controller pages.
     *
     */
    public class RedirectPath
    extends PathBuilder
        {
        public RedirectPath()
            {
            super(
                REDIRECT_PREFIX
                );
            }

        public RedirectPath(String path)
            {
            this();
            this.append(
                path
                );
            }
        }

    /**
     * Inner class for links to MCV controller pages.
     *
     */
    public class PagePath
    extends PathBuilder
        {

        public PagePath()
            {
            super(
                request.getContextPath()
                );
            this.append(
                SERVLET_PATH
                );
            }

        public PagePath(String path)
            {
            this();
            this.append(
                path
                );
            }
        }

    /**
     * Inner class for links to static content.
     *
     */
    public class FilePath
    extends PathBuilder
        {
        public FilePath(String path)
            {
            super(
                request.getContextPath()
                );
            this.append(
                STATIC_PATH
                );
            this.append(
                path
                );
            }
        }

    /**
     * Create a PathBuilder for static content.
     *
     */
    public PathBuilder file(String path)
        {
        return new FilePath(
            path
            );
        }

    /**
     * Build a link based on our webapp context.
     *
     */
    public PathBuilder link(String path)
        {
        return new PagePath(
            path
            );
        }

    /**
     * Link to the home page.
     *
     */
    public PathBuilder home()
        {
        return new PagePath(
            Paths.HOME_PATH
            );
        }

    /**
     * Link to an Account.
     *
     */
    public PathBuilder link(Account account)
        {
        PathBuilder builder = new PagePath();
        builder.append(
            account
            );
        return builder ;
        }

    /**
     * Link to an Account.
     *
     */
    public PathBuilder link(Account account, String path)
        {
        PathBuilder builder = new PagePath();
        builder.append(
            account
            );
        builder.append(
            path
            );
        return builder;
        }

    /**
     * Link to a Tag.
     *
     */
    public PathBuilder link(Tag tag)
        {
        PathBuilder builder = new PagePath();
        builder.append(
            tag
            );
        return builder;
        }

    /**
     * Link to a Tag.
     *
     */
    public PathBuilder link(Tag tag, String path)
        {
        PathBuilder builder = new PagePath();
        builder.append(
            tag
            );
        builder.append(
            path
            );
        return builder;
        }

    /**
     * Link to a Job.
     *
     */
    public PathBuilder link(Job job)
        {
        PathBuilder builder = new PagePath();
        builder.append(
            job
            );
        return builder;
        }

    /**
     * Link to a Job.
     *
     */
    public PathBuilder link(Job job, String path)
        {
        PathBuilder builder = new PagePath();
        builder.append(
            job
            );
        builder.append(
            path
            );
        return builder;
        }

    /**
     * Link to a TapService.
     *
     */
    public PathBuilder link(TapService service)
        {
        PathBuilder builder = new PagePath();
        builder.append(
            service
            );
        return builder;
        }

    /**
     * Link to a TapService.
     *
     */
    public PathBuilder link(TapService service, String path)
        {
        PathBuilder builder = new PagePath();
        builder.append(
            service
            );
        builder.append(
            path
            );
        return builder;
        }

    /**
     * Link to a TapTable.
     *
     */
    public PathBuilder link(TapTable table)
        {
        PathBuilder builder = new PagePath();
        builder.append(
            table
            );
        return builder;
        }

    /**
     * Link to a TapColumn.
     *
     */
    public PathBuilder link(TapColumn column)
        {
        PathBuilder builder = new PagePath();
        builder.append(
            column
            );
        return builder;
        }

    /**
     * Link to a TapRow.
     *
     */
    public PathBuilder link(TapRow row)
        {
        PathBuilder builder = new PagePath();
        builder.append(
            row
            );
        return builder;
        }

    /**
     * Link to a TapJoin.
     *
     */
    public PathBuilder link(TapJoin join)
        {
        PathBuilder builder = new PagePath();
        builder.append(
            join
            );
        return builder;
        }

    /**
     * Link to a RowTag.
     *
     */
    public PathBuilder link(RowTag rowtag)
        {
        PathBuilder builder = new PagePath();
        builder.append(
            rowtag
            );
        return builder;
        }

    /**
     * Link to a JoinTag.
     *
     */
    public PathBuilder link(JoinTag jointag)
        {
        PathBuilder builder = new PagePath();
        builder.append(
            jointag
            );
        return builder;
        }



    /**
     * Redirect to the home page.
     *
     */
    public String redirect()
        {
        PathBuilder builder = new RedirectPath(
            Paths.HOME_PATH
            );
        return builder.toString();
        }

    /**
     * Redirect to an Account.
     *
     */
    public String redirect(Account account)
        {
        PathBuilder builder = new RedirectPath();
        builder.append(
            account
            );
        return builder.toString();
        }

    /**
     * Redirect to an Account.
     *
     */
    public String redirect(Account account, String path)
        {
        PathBuilder builder = new RedirectPath();
        builder.append(
            account
            );
        builder.append(
            path
            );
        return builder.toString();
        }

    /**
     * Redirect to a Tag.
     *
     */
    public String redirect(Tag tag)
        {
        PathBuilder builder = new RedirectPath();
        builder.append(
            tag
            );
        return builder.toString();
        }

    /**
     * Redirect to a Job.
     *
     */
    public String redirect(Job job)
        {
        PathBuilder builder = new RedirectPath();
        builder.append(
            job
            );
        return builder.toString();
        }

    /**
     * Create a QRCode path.
     *
     */
    public String qrcode(String path)
        {
        return qrcode(
            new PathBuilder(
                path
                )
            );
        }

    /**
     * Create a QRCode path.
     *
     */
    public String qrcode(PathBuilder builder)
        {
        builder.append(
            Paths.QRCODE_PATH
            );
        return builder.toString() ;
        }

    }

